#ifndef mbObj
#include "bsp.h"
#include "pincfg.h"
#include "at32f435_437_usart.h"
#include "os_obj.h"
#include "mbapp.h"
#include "com_def.h"
#define mbRxEnable()
#define mbTxEnable()
mb_obj_type mbObj;
#define mbPORT USART3
#define mbURT_IRQn USART3_IRQn
static void mb_cb_set(void)
{
}
static void mb_port_hal_cfg(void) {}
#endif

static void mb_cb_set(void);
static void mbObjInit(mb_mode_type mbMode);
static void mbPortTx1Rx0Enable(uint8_t mode);
static void mb_port_Init(mb_mode_type mbMode, uint32_t ulBaudRate, mb_parity_type eParity);
static void mbDataSend(void);
static void mb_port_hal_cfg(void);
static void (*mb_byte_send)(uint8_t dat);

/*****************************************************************************
 * @brief UART OPT
 *****************************************************************************/
// 数据收发
#define UART_SEND_DAT(dat) mbPORT->dt = dat
#define UART_RCV_DAT() mbPORT->dt

// 缓冲状态
#define UART_RX_NE_ST() ((mbPORT->sts & USART_RDBF_FLAG) != 0) // rx not empty
#define UART_TX_NF_ST() (0 != (mbPORT->sts & USART_TDBE_FLAG)) // tx not full
#define UART_TX_TC_ST() (mbPORT->sts & (USART_TDC_FLAG))
#define UART_TX_TC_CLR()

// 接收控制
#define UART_RX_EN() mbPORT->ctrl1_bit.ren = 1
#define UART_RX_INT_EN() mbPORT->ctrl1_bit.rdbfien = 1
#define UART_RX_INT_DIS()      \
	mbPORT->ctrl1_bit.ren = 0; \
	mbPORT->ctrl1_bit.rdbfien = 0

// 发送控制
#define UART_TX_EN() mbPORT->ctrl1_bit.ten = 1
#define UART_TX_TDE_EN()          \
	mbPORT->ctrl1_bit.tdcien = 0; \
	mbPORT->ctrl1_bit.tdbeien = 1
#define UART_TX_TC_EN()            \
	mbPORT->ctrl1_bit.tdbeien = 0; \
	mbPORT->ctrl1_bit.tdcien = 1
#define UART_TX_INT_DIS()          \
	mbPORT->ctrl1_bit.tdbeien = 0; \
	mbPORT->ctrl1_bit.tdcien = 0

// 错误标志及清除
#define UART_RX_ERR_FLAG (USART_PERR_FLAG | USART_ROERR_FLAG)
#define UART_RX_ERR_CLR()

/*****************************************************************************
 * @brief mb_byte_send
 * @param   dat
 * @return  none
 * @ Pass/ Fail criteria: none
 *****************************************************************************/

static void mb_rtu_byte_send(uint8_t dat)
{
	mbPORT->dt = dat;
}

static void mb_asc_byte_send(uint8_t dat)
{
	mbPORT->dt = dat;
}

/*****************************************************************************
 * @brief UART interrupt routine.
 * @param   none
 * @return  none
 *****************************************************************************/
void mbISR()
{
	volatile uint32_t IntSt;
	volatile uint8_t Data;

	mbObj.timeout_cnt = 0;

	IntSt = mbPORT->sts;

	if (IntSt & USART_RDBF_FLAG)
	{
		Data = UART_RCV_DAT();

		if ((IntSt & UART_RX_ERR_FLAG) != 0)
		{
			if (mbObj.rcv_cnt >= 1)
			{
				mbObj.err_st.bits.hal = 1;
			}
			UART_RX_ERR_CLR();
		}

		mb_data_rcv(&mbObj, Data);
	}
	else if ((mbObj.snd_size <= mbObj.snd_cnt) && (IntSt & USART_TDC_FLAG))
	{
		mb_send_end(&mbObj);
		mbPortTx1Rx0Enable(0);
		UART_TX_TC_CLR();
	}
	else if (IntSt & USART_TDBE_FLAG)
	{
		if (mb_data_send(&mbObj, mb_byte_send, 1))
		{
			UART_TX_TC_EN();
		}
	}
	else
	{
	}
}

/*****************************************************************************
 * @brief   	com modle init .
 * @param   none
 * @return  none
 * @ Pass/ Fail criteria: none
 *****************************************************************************/
static void mb_port_Init(mb_mode_type mbMode, uint32_t ulBaudRate, mb_parity_type eParity)
{
	usart_data_bit_num_type dat_bits;
	usart_stop_bit_num_type stop_bits;
	usart_parity_selection_type parity;

	mb_port_hal_cfg();

	mbObjInit(mbMode);

	mb_byte_send = mb_rtu_byte_send;

	if (mbMode == MB_RTU_MASTER || mbMode == MB_RTU_SLAVE)
	{
		// rtu mode
		if (MB_PAR_NONE == eParity)
		{
			dat_bits = USART_DATA_8BITS;
			stop_bits = USART_STOP_2_BIT;
			parity = USART_PARITY_NONE;
		}
		else if (MB_PAR_NONE_1S == eParity)
		{
			dat_bits = USART_DATA_8BITS;
			stop_bits = USART_STOP_1_BIT;
			parity = USART_PARITY_NONE;
		}
		else if (MB_PAR_ODD == eParity)
		{
			dat_bits = USART_DATA_9BITS;
			stop_bits = USART_STOP_1_BIT;
			parity = USART_PARITY_ODD;
		}
		else
		{
			dat_bits = USART_DATA_9BITS;
			stop_bits = USART_STOP_1_BIT;
			parity = USART_PARITY_EVEN;
		}

		mbObj.run_st.bits.rtu_mode = 1;
	}
	else
	{
		mb_byte_send = mb_asc_byte_send;

		// asc mode
		if (MB_PAR_NONE == eParity)
		{
			dat_bits = USART_DATA_7BITS;
			stop_bits = USART_STOP_2_BIT;
			parity = USART_PARITY_NONE;
		}
		else if (MB_PAR_NONE_1S == eParity)
		{
			dat_bits = USART_DATA_7BITS;
			stop_bits = USART_STOP_1_BIT;
			parity = USART_PARITY_NONE;
		}
		else if (MB_PAR_ODD == eParity)
		{
			dat_bits = USART_DATA_8BITS;
			stop_bits = USART_STOP_1_BIT;
			parity = USART_PARITY_ODD;
		}
		else
		{
			dat_bits = USART_DATA_8BITS;
			stop_bits = USART_STOP_1_BIT;
			parity = USART_PARITY_EVEN;
		}

		mbObj.run_st.bits.rtu_mode = 0;
	}

	// rtu timer
	if (mbObj.run_st.bits.rtu_mode == 0)
	{
		mbObj.rtu_timer_sv = 240;
		mbObj.timeout_set = 500;
	}
	else
	{
		if (ulBaudRate > 19200)
		{
			mbObj.rtu_timer_sv = 3;
		}
		else
		{
			mbObj.rtu_timer_sv = (com_timer_cal(ulBaudRate, (35 * 11 + 9) / 10, 300, 12000) + 99) / 100;
		}
	}

	usart_init(mbPORT, ulBaudRate, dat_bits, stop_bits);
	usart_parity_selection_config(mbPORT, parity);
	usart_enable(mbPORT, TRUE);

	nvic_irq_set(mbURT_IRQn, 0x06, 1);

	mbPortTx1Rx0Enable(0);

	UART_TX_EN();
}

/*****************************************************************************
 *
 * @brief   Uart En or Dis.
 *
 * @param   none
 *
 * @return  none
 *
 * @ Pass/ Fail criteria: none
 *****************************************************************************/

static void mbPortTx1Rx0Enable(uint8_t mode)
{
	volatile uint8_t u8Temp;

	if (0 == mode)
	{
		mbRxEnable();

		UART_TX_INT_DIS();
		UART_RX_EN();

		u8Temp = mbPORT->dt;
		while ((mbPORT->sts & (USART_RDBF_FLAG | USART_ROERR_FLAG)) != 0)
		{
			u8Temp = mbPORT->dt;
			__DSB();
		}

		UART_RX_INT_EN();
	}
	else
	{
		mbTxEnable();

		UART_RX_INT_DIS();

		UART_TX_TDE_EN();
	}
}

/*****************************************************************************
 *
 * @brief   Send data.
 *
 * @param   none
 *
 * @return  none
 *
 * @ Pass/ Fail criteria: none
 *****************************************************************************/
static void mbDataSend(void)
{
	mbPortTx1Rx0Enable(1);
}

/*****************************************************************************
 *
 * @brief   mb object init.
 *
 * @param   none
 *
 * @return  TURE
 *
 * @ Pass/ Fail criteria: none
 *****************************************************************************/
static void mbObjInit(mb_mode_type mbMode)
{

	mb_obj_init(&mbObj);
	mbObj.adu_send = &mbDataSend;

	mb_cb_set();

	mbObj.master.err_cnt = 0;

	// SLAVE FUNCTION INIT
	if (MB_RTU_MASTER == mbMode || mbMode == MB_ASCII_MASTER)
	{
		mbObj.run_st.bits.master_mode = 1;
	}
	else
	{
		mbObj.run_st.bits.master_mode = 0;
	}
}

/*****************************************************************************
 * @brief   sim_mbport_keep
 * @param   none
 * @return  none
 *****************************************************************************/
#ifndef mbObj
void sim_mbport_keep(void)
{
	mb_port_Init(MB_RTU_SLAVE, 9600, MB_PAR_NONE);
}
#endif